Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds ILP solver ENV checks for GUROBI and CPLEX #206

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions org.emoflon.gips.core/src/org/emoflon/gips/core/milp/CplexSolver.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.emoflon.gips.core.milp;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -29,6 +30,8 @@
import org.emoflon.gips.core.milp.model.WeightedLinearFunction;
import org.emoflon.gips.core.util.SystemUtil;

import com.gurobi.gurobi.GRB;

import ilog.concert.IloException;
import ilog.concert.IloIntVar;
import ilog.concert.IloLinearNumExpr;
Expand Down Expand Up @@ -72,9 +75,110 @@ public class CplexSolver extends Solver {
public CplexSolver(final GipsEngine engine, final SolverConfig config) {
super(engine);
this.config = config;
checkEnvJarCompatibility();
init();
}

/**
* Checks all two necessary system environment variables to match the used CPLEX
* version. Expected is that the configured ENVs contain the exact same version
* number as the Java class(es) provided by the CPLEX JAR.
*/
private void checkEnvJarCompatibility() {
checkCplexVersionInEnv("LD_LIBRARY_PATH");
checkCplexVersionInEnv("PATH");
}

/**
* Checks if the system environment variable with the name 'envName' contains
* the exact version number of the used CPLEX JAR file.
*
* @param envName System environment variable to check the CPLEX version in.
*/
private void checkCplexVersionInEnv(String envName) {
if (envName == null || envName.isBlank()) {
throw new IllegalArgumentException("Given ENV name was null or empty.");
}

// Get system ENV
final String envValue = System.getenv(envName);

if (envValue == null || envValue.isBlank()) {
throw new IllegalStateException("The ENV '" + envName + "' was null or empty.");
}

// Get version string(s) from folder path
String[] folderSegments = null;
if (envValue.contains("/")) {
folderSegments = envValue.split("/");
} else if (envValue.contains("\\")) {
folderSegments = envValue.split("\\");
}

if (folderSegments == null) {
throw new InternalError();
}

String cplexSubFolder = "";
for (int i = 0; i < folderSegments.length; i++) {
if (folderSegments[i] != null && folderSegments[i].contains("CPLEX_Studio")) {
cplexSubFolder = folderSegments[i];
break;
}
}

final String versionString = cplexSubFolder.substring( //
cplexSubFolder.lastIndexOf("o") + 1, cplexSubFolder.length());

// Sanity check
if (versionString.length() != 4) {
throw new InternalError();
}

// split version string up into its parts
final String envVersion = versionString.substring(0, 4);

String cplexVersion = "";

try {
// E.g.: 22010100L
final Field versionField = IloCplex.class.getDeclaredField("serialVersionUID");
versionField.setAccessible(true);
cplexVersion = String.valueOf(versionField.getLong(null));
} catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}

// Sanity check
if (versionString.length() != 4) {
throw new InternalError();
}
if (cplexVersion.length() != 8) {
throw new InternalError();
}

// Got a string like 22010100, so we have to split it up
final String major = cplexVersion.substring(0, 2);
final String minor = cplexVersion.substring(2, 4);
final String technical = cplexVersion.substring(4, 6);
// The remaining string (`00` in this case) does not matter

// Assemble the CPLEX version string as we expect it
// Please notice: this may break if the minor or technical version will be
// larger than `9`
final String assembledCplexVersion = major + minor.substring(1) + technical.substring(1);

// Actual check of the version(s)
if (!assembledCplexVersion.equals(envVersion)) {
throw new UnsupportedOperationException(
"You configured the wrong CPLEX version in your '" + envName + "' ENV. Expected: '" //
+ assembledCplexVersion //
+ "', configured: '" //
+ envVersion //
+ "'.");
}
}

private void init() {
try {
cplex = new IloCplex();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,83 @@ public class GurobiSolver extends Solver {
public GurobiSolver(final GipsEngine engine, final SolverConfig config) throws Exception {
super(engine);
this.config = config;
checkEnvJarCompatibility();
init();
}

/**
* Checks all three necessary system environment variables to match the used
* GUROBI version. Expected is that the configured ENVs contain the exact same
* version number as the Java class(es) provided by the GUROBI JAR.
*/
private void checkEnvJarCompatibility() {
checkGurobiVersionInEnv("GUROBI_HOME");
checkGurobiVersionInEnv("LD_LIBRARY_PATH");
checkGurobiVersionInEnv("PATH");
}

/**
* Checks if the system environment variable with the name 'envName' contains
* the exact version number of the used GUROBI JAR file.
*
* @param envName System environment variable to check the GUROBI version in.
*/
private void checkGurobiVersionInEnv(final String envName) {
if (envName == null || envName.isBlank()) {
throw new IllegalArgumentException("Given ENV name was null or empty.");
}

// Get system ENV
final String envValue = System.getenv(envName);

if (envValue == null || envValue.isBlank()) {
throw new IllegalStateException("The ENV '" + envName + "' was null or empty.");
}

// Get version string(s) from folder path
String[] folderSegments = null;
if (envValue.contains("/")) {
folderSegments = envValue.split("/");
} else if (envValue.contains("\\")) {
folderSegments = envValue.split("\\");
}

if (folderSegments == null) {
throw new InternalError();
}

String gurobiSubFolder = "";
for (int i = 0; i < folderSegments.length; i++) {
if (folderSegments[i] != null && folderSegments[i].contains("gurobi")) {
gurobiSubFolder = folderSegments[i];
break;
}
}

final String versionString = gurobiSubFolder.substring( //
gurobiSubFolder.lastIndexOf("i") + 1, gurobiSubFolder.length());

// Sanity check
if (versionString.length() != 4) {
throw new InternalError();
}

// split version string up into its parts
final int major = Integer.valueOf(versionString.substring(0, 2));
final int minor = Integer.valueOf(versionString.substring(2, 3));
final int technical = Integer.valueOf(versionString.substring(3, 4));

// Actual check of the version(s)
if (major != GRB.VERSION_MAJOR || minor != GRB.VERSION_MINOR || technical != GRB.VERSION_TECHNICAL) {
throw new UnsupportedOperationException(
"You configured the wrong GUROBI version in your '" + envName + "' ENV. Expected: '" //
+ GRB.VERSION_MAJOR + GRB.VERSION_MINOR + GRB.VERSION_TECHNICAL //
+ "', configured: '" //
+ major + minor + technical //
+ "'.");
}
}

private void init() throws Exception {
final var out = System.out;
final var err = System.err;
Expand Down